/*
 * Matrix.h
 *
 *  Created on: May 26, 2011
 *      Author: gilang
 */

#ifndef MATRIX_H_
#define MATRIX_H_
#include <iomanip>

class Matrix {
private:
	double **values;
	int row;
	int coloumn;
public:
	Matrix() {
		values = NULL;
		row = 0;
		coloumn = 0;
	}

	Matrix(const Matrix *m){
		this->values=m->values;
		this->row=m->row;
		this->coloumn=m->coloumn;
	}
	Matrix(int b, int k) {
		row = b;
		coloumn = k;
		values = new double*[b + 1];
		for (int i = 0; i <= b; i++) {
			values[i] = new double[k + 1];
		}
	}


	void set(int i, int j, double t) {
		values[i][j] = t;
	}
	double & operator()(int i, int j) {
		return values[i][j];
	}

	Matrix operator+(const Matrix &m) {
		Matrix x = Matrix(m.row, m.coloumn);
		double **v = x.values;
		for (int i = 1; i <= x.row; i++) {
			for (int j = 1; j <= x.coloumn; j++) {
				v[i][j] = values[i][j] + m.values[i][j];
			}
		}
		return x;
	}
	Matrix operator-(const Matrix &m) {
		Matrix x = Matrix(m.row, m.coloumn);
		double **v = x.values;
		for (int i = 1; i <= x.row; i++) {
			for (int j = 1; j <= x.coloumn; j++) {
				v[i][j] = values[i][j] - m.values[i][j];
			}
		}
		return x;
	}

	Matrix operator*(const Matrix &m) {
		Matrix x = Matrix(m.row, m.coloumn);
		double **v = x.values;
		for (int i = 1; i <= x.row; i++) {
			for (int j = 1; j <= x.coloumn; j++) {
				v[i][j] = 0;
				for (int k = 1; k <= coloumn; k++)
					v[i][j] += values[i][k] * m.values[k][j];
			}
		}
		return x;
	}

	Matrix operator*(const double &m) {
		for (int i = 1; i <= row; i++) {
			for (int j = 1; j <= coloumn; j++) {
				values[i][j] = m * values[i][j];
			}
		}
		return *this;
	}

	Matrix operator=(const Matrix &m) {
		row = m.row;
		coloumn = m.coloumn;
		values = m.values;
		return *this;
	}


	Matrix & operator+=(const Matrix &m) {
		for (int i = 1; i <= row; i++) {
			for (int j = 1; j <= coloumn; j++) {
				values[i][j] += m.values[i][j];
			}
		}
		return *this;
	}

	Matrix & operator-=(const Matrix &m) {
		for (int i = 1; i <= row; i++) {
			for (int j = 1; j <= coloumn; j++) {
				values[i][j] -= m.values[i][j];
			}
		}
		return *this;
	}

	double determinant(){
		double p=1;
		this->rowOperation();
		for(int i=1;i<=row;i++){
			p*=this->operator ()(i,i);
		}
		return p;
	}

	void rowOperation(){
		double m;
		for(int k=1;k<=row-1;k++)
			for(int i=k+1;i<=coloumn;i++){
				m=values[i][k]/values[k][k];
				for(int j=1;j<=coloumn;j++)
					values[i][j]-=m*values[k][j];
			}
	}

	static Matrix copyValueOf(Matrix &m){
		Matrix n=Matrix(m.row,m.coloumn);
		n+=m;
		return n;
	}

	double **getValues() {
		return values;
	}

	int getRow() const {
		return row;
	}
	int getCol() const {
		return coloumn;
	}

	virtual ~Matrix() {
	}
};

#endif /* MATRIX_H_ */
